﻿using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using AzukiMap.Layer;
using AzukiMap.Tools.Logger;
using GeoAPI.Geometries;
using Point=GisSharpBlog.NetTopologySuite.Geometries.Point;
using System.Collections.Generic;

namespace AzukiMap.Renderer
{
    public class TrianglePrimitiveRenderer : RasterRendererCore
    {
        public TrianglePrimitiveRenderer(MapLayer layer)
            : base(layer)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="imageExtent">A image extent by a polygon. This should be clock wise and used only 4 points.</param>
        /// <param name="imageUri"></param>
        public override IList<FrameworkElement> CreateImages(Uri imageUri, IPolygon imageExtent)
        {
            return CreateImages(imageExtent, imageUri, false);
        }

        public override bool IsFitToDraw(IPolygon imagePolyOnMap, ImageMidPoints imageMidpointsOnMap)
        {
            double geoWidth = imagePolyOnMap.EnvelopeInternal.Width;
            double geoHeight = imagePolyOnMap.EnvelopeInternal.Height;
            double imageWidth = GetImageWidth(geoWidth);
            double imageHeight = GetImageHeight(geoHeight);
            double perPixX = geoWidth / imageWidth;
            double perPixY = geoHeight / imageHeight;

            //ICoordinate origin = new Coordinate(imagePolyOnMap.EnvelopeInternal.MinX, imagePolyOnMap.EnvelopeInternal.MaxY);
            IPoint origin = new Point(imagePolyOnMap.EnvelopeInternal.MinX, imagePolyOnMap.EnvelopeInternal.MaxY);

            var imageTL = GetPointOnImage(imagePolyOnMap.ExteriorRing.GetPointN(0), origin, perPixX,
                                                           perPixY);
            var imageBL = GetPointOnImage(imagePolyOnMap.ExteriorRing.GetPointN(1), origin, perPixX,
                                                           perPixY);
            var imageBR = GetPointOnImage(imagePolyOnMap.ExteriorRing.GetPointN(2), origin, perPixX,
                                                           perPixY);
            var imageTR = GetPointOnImage(imagePolyOnMap.ExteriorRing.GetPointN(3), origin, perPixX,
                                                           perPixY);

            // Check if the center left point is in the acceptable point.
            var imageCL = GetPointOnImage(imageMidpointsOnMap.onMapCL, origin, perPixX, perPixY);
            var correctCL = GetMidpoint(imageTL, imageBL);
            if (!IsAccuratedPoint(imageCL, correctCL))
                return false;

            var imageCR = GetPointOnImage(imageMidpointsOnMap.onMapCR, origin, perPixX, perPixY);
            var correctCR = GetMidpoint(imageTR, imageBR);
            if (!IsAccuratedPoint(imageCR, correctCR))
                return false;

            var imageTC = GetPointOnImage(imageMidpointsOnMap.onMapTC, origin, perPixX, perPixY);
            var correctTC = GetMidpoint(imageTL, imageTR);
            if (!IsAccuratedPoint(imageTC, correctTC))
                return false;

            var imageBC = GetPointOnImage(imageMidpointsOnMap.onMapBC, origin, perPixX, perPixY);
            var correctBC = GetMidpoint(imageBL, imageBR);
            if (!IsAccuratedPoint(imageBC, correctBC))
                return false;

            var imageCC = GetPointOnImage(imageMidpointsOnMap.onMapCC, origin, perPixX, perPixY);
            var correctCC = GetMidpoint(imageTL, imageBR);
            if (!IsAccuratedPoint(imageCC, correctCC))
                return false;

            return true;
        }

        //public override IList<FrameworkElement> CreateImages(Uri imageUri, IPolygon imageBoundary)
        private IList<FrameworkElement> CreateImages(IPolygon imageBoundary, Uri imageUri, bool isClockWise)
        {
            var images = new List<FrameworkElement>();

            ICoordinate[] coords = imageBoundary.Coordinates;

            // the extent should have 4 points.
            if (coords.Length < 4)
            {
                Logger.Warn("AzukiMap.Renderer.RasterRenderer.DrawRaster: imageExtent should have 4 points");
                return null;
            }
            ImageTriangle imageTl = CreateImageTriangleTopLeft(coords, imageUri, isClockWise);
            //_layer.Children.Add(imageTl);
            images.Add(imageTl);

            ImageTriangle imageBr = CreateImageTriangleBottomRight(coords, imageUri, isClockWise);
            //_layer.Children.Add(imageBr);
            images.Add(imageBr);

            return images;
        }

        private ImageTriangle CreateImageTriangleTopLeft(ICoordinate[] coords, Uri imageUri, bool isClockWise)
        {
            var imageTriangle = new ImageTriangle();
            var source = new BitmapImage(imageUri);

            // TODO: this makes a memory leak problem. 
#if SILVERLIGHT
            //source.ImageFailed += source_ImageFailed;
#else
            //source.DownloadFailed += new EventHandler<ExceptionEventArgs>(source_DownloadFailed);
#endif
            imageTriangle.TextureSource = source;

            // top left
            imageTriangle.Point1 = GetPixPoint(coords[0]);
            // top right
            imageTriangle.Point2 = isClockWise ? GetPixPoint(coords[1]) : GetPixPoint(coords[3]);
            // bottom left
            imageTriangle.Point3 = isClockWise ? GetPixPoint(coords[3]) : GetPixPoint(coords[1]);

            // set positions
            var pc = new PointCollection
                         {
                             new System.Windows.Point(0, 0), // top left
                             new System.Windows.Point(1, 0), // top right
                             new System.Windows.Point(0, 1)  // bottom left
                         };
            imageTriangle.TexturePositions = pc;

            return imageTriangle;
        }

        private ImageTriangle CreateImageTriangleBottomRight(ICoordinate[] coords, Uri imageUri, bool isClockWise)
        {
            var imageTriangle = new ImageTriangle();
            var source = new BitmapImage(imageUri);
#if SILVERLIGHT
            //source.ImageFailed += source_ImageFailed;
#else
            //source.DownloadFailed += new EventHandler<ExceptionEventArgs>(source_DownloadFailed);
#endif
            imageTriangle.TextureSource = source;

            // top right 
            imageTriangle.Point1 = isClockWise ? GetPixPoint(coords[1]) : GetPixPoint(coords[3]);
            // bottom left 
            imageTriangle.Point2 = isClockWise ? GetPixPoint(coords[3]) : GetPixPoint(coords[1]);
            // bottom right 
            imageTriangle.Point3 = GetPixPoint(coords[2]);

            // set positions
            var pc = new PointCollection
                         {
                             new System.Windows.Point(1, 0), // top right
                             new System.Windows.Point(0, 1), // bottom left
                             new System.Windows.Point(1, 1)  // bottom right
                         };
            imageTriangle.TexturePositions = pc;

            return imageTriangle;
        }


    }
}